/*
 * Copyright 2009-2010 the original author or authors.
 *
 * Licensed under the Apache license, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.internna.iwebjtracker.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import javax.persistence.MappedSuperclass;
import org.internna.iwebmvc.model.Document;
import org.internna.iwebmvc.model.MultiDocument;

/**
 * Different operations available on the collections of an issue.
 *
 * @author Jose Noheda
 * @since 1.0
 */
@MappedSuperclass
public abstract class IssueCollectionManager extends IssueActivityManager {

    private static final long serialVersionUID = -1457831334622841312L;

    /**
     * Adds a user to the collection of voters
     *
     * @param user any
     * @return true if the user has been added to the collection of voters
     */
    @Override public final boolean vote(TrackerUser user) {
        if (user != null) {
            if (voters == null) {
                voters = new HashSet<TrackerUser>();
            }
            if ((!voters.contains(user)) && voters.add(user)) {
                return onVote(user);
            }
        }
        return false;
    }

    /**
     * Extension point inherited by subclasses when a votes was successfully casted.
     *
     * @param user a non null user
     * @return the final operation result
     */
    protected abstract boolean onVote(TrackerUser user);

    /**
     * Adds the user to the set of watchers.
     *
     * @param user any
     * @return true if the set of watchers has one more member
     */
    @Override public final boolean watch(TrackerUser user) {
        if (user != null) {
            if (watchers == null) {
                watchers = new HashSet<TrackerUser>();
            }
            if (!watchers.contains(user)) {
                return watchers.add(user);
            }
        }
        return false;
    }

    /**
     * Extension point inherited by subclasses when a watcher was successfully registered.
     *
     * @param user a non null user
     * @return the final operation result
     */
    protected abstract boolean onWatch(TrackerUser user);

    /**
     * Creates a list from the comments collection and orders it according to their natural ordering
     *
     * @return a non null non modifiable list
     */
    @Override public List<IssueComment> getCommentsByDate() {
        List<IssueComment> ordered = new ArrayList<IssueComment>(getComments());
        Collections.sort(ordered);
        return Collections.unmodifiableList(ordered);
    }

    /**
     * Adds a new comment to this issue.
     *
     * @param comment any
     */
    public final boolean addComment(IssueComment comment) {
        if (comment != null) {
            if (comments == null) {
                comments = new HashSet<IssueComment>();
            }
            if (comments.add(comment)) {
                return onAddComment(comment);
            }
        }
        return false;
    }

    /**
     * Extension point inherited by subclasses called when a comment was successfully entered.
     *
     * @param comment a non null instance
     * @return the final operation result
     */
    protected abstract boolean onAddComment(IssueComment comment);

    /**
     * Adds a new Document to the attachments object (creating one if needed).
     *
     * @param doc any
     */
    @Override public MultiDocument addAttachment(TrackerUser user, Document doc) {
        if ((doc != null) && (doc.getId() != null)) {
            if (attachments == null) {
                attachments = new MultiDocument();
            }
            return onAddAttachment(attachments.addDocument(doc), user, doc);
        }
        return null;
    }

    /**
     * Extension point inherited by subclasses called when a doc was added.
     *
     * @param md any
     * @param doc a non null instance
     * @return any
     */
    protected abstract MultiDocument onAddAttachment(MultiDocument md, TrackerUser user, Document doc);

}
